spring Java泛型和枚举,模板参数丢失
我有一个相当复杂的结构,它没有按预期工作。我就是这么做的:
public interface ResultServiceHolder {
<M, ID extends Serializable, BO extends BusinessObject<M, ID>> ResultService<M, ID, BO> getService();
}
public enum ResultTypes implements ResultServiceHolder {
RESULT_TYPE_ONE {
@Override
public ResultOneService getService() { //unchecked conversion?
return serviceInitializer.getResultOneService();
}
},
RESULT_TYPE_TWO {
@Override
public ResultTwoService getService() { //unchecked conversion?
return serviceInitializer.getResultTwoService();
}
},
RESULT_TYPE_THREE {
@Override
public ResultThreeService getService() { //unchecked conversion?
return serviceInitializer.getResultThreeService();
}
};
protected ServiceInitializer serviceInitializer;
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
@Component
public static class ServiceInitializer {
@Autowired
private ResultOneService resultOneService;
@Autowired
private ResultTwoService resultTwoService;
@Autowired
private ResultThreeService resultThreeService;
@PostConstruct
public void init() {
for(ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
//getters
}
}
其目的是基于枚举来泛化调用,而只是能够在枚举数组上进行迭代
for(ResultServiceHolder resultServiceHolder : ResultTypes.values()) {
if(resultServiceHolder.equals(post.getPostResultTypeCode())) {
return resultServiceHolder.getService().createResultSearchCriteriaResponse(postId);
}
}
这很好,很好用。然而,如果我说
ResultTypes.RESULT_TYPE_ONE.getService().getRepository()
然后它是一个BaseRepository<Object, Serializable>
而不是一个BaseRepository<ResultTypeOne, Long>
。方法resultTypeHolder.getService()
返回ResultService<M, ID, BO>
,但最终变成Object
和Serializable
我做错了什么如何保留通用参数类型
我想补充一点,是的,我确实意识到问题在于未经检查的铸造。但这些服务被定义为
public interface ResultTypeOneService
extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> {
}
我不知道为什么不能推断出这些类型
编辑:从技术上讲,如果我明确推断出:
ResultTypes.RESULT_TYPE_ONE.<ResultTypeOne, Long, ResultTypeOneBO>getService().getRepository()
但它应该是自动的,为什么不能自动工作呢?我应该为它提供某种包含类型的对象吗?为什么返回类型不足以实现这一点
EDIT2:的超类是
@SuppressWarnings("serial")
@EntityListeners(EntityListener.class)
@MappedSuperclass
public abstract class EntityBase implements Serializable {
但它没有映射到边界中的任何位置
EDIT3:非常感谢@Radiodef!理论上的解决方案是这样的,而且效果非常好:
public interface ResultServiceHolder<M, ID extends Serializable, BO extends BusinessObject<M, ID>> {
ResultService<M, ID, BO> getService();
}
public abstract class ResultTypes<M, ID extends Serializable, BO extends BusinessObject<M, ID>>
implements ResultServiceHolder<M, ID, BO> {
public static ResultTypes<?, ?, ?>[] values() {
return new ResultTypes<?, ?, ?>[] {RESULT_ONE, RESULT_TWO, RESULT_THREE};
}
public static final ResultTypes<ResultOne, Long, ResultOneBO> RESULT_ONE = new ResultTypes<ResultOne, Long, ResultOneBO>("Result One") {
@Override
public ResultOneService getService() {
return serviceInitializer.resultOneService;
}
};
public static final ResultTypes<ResultTwo, Long, ResultTwoBO> RESULT_TWO = new ResultTypes<ResultTwo, Long, ResultTwoBO>("Result Two") {
@Override
public ResultTwoService getService() {
return serviceInitializer.resultTwoService;
}
};
public static final ResultTypes<ResultThree, Long, ResultThreeBO> RESULT_THREE = new ResultTypes<ResultThree, Long, ResultThreeBO>("Result Three") {
@Override
public ResultThreeService getService() {
return serviceInitializer.resultThreeService;
}
};
protected String name;
protected ServiceInitializer serviceInitializer;
private ResultTypes(String name) {
this.name = name;
}
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
@Component
static class ServiceInitializer {
@Autowired
private ResultOneService resultOneService;
@Autowired
private ResultTwoService resultTwoService;
@Autowired
private ResultThreeService resultThreeService;
@PostConstruct
public void init() {
for (ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
}
}
我认为,由于解决方案会变得很长,我将坚持enum
方法,并接受这种边界损失。我必须添加自己的values()
实现,这比强制执行这些边界所获得的更多。然而,这是一个有趣的理论练习,再次感谢您的帮助
# 1 楼答案
好的,首先你需要理解为什么你正在做的可能不是你认为它正在做的。让我们看一个更简单的例子
这里有一个通用方法,
get
。泛型方法的类型参数取决于调用站点提供的内容。例如:当你像这样覆盖它的时候
这是你能够做的事情(只是因为擦除),但你可能不应该做。它只允许向后兼容非泛型代码。你应该听从警告,而不是去做。这样做意味着,例如,我仍然可以过来,命令它返回其他东西:
这就是为什么存在未经检查的转换
您可能的意思是使用通用接口声明:
现在
T
的参数取决于对象引用的类型我们可以像这样实施它
此外,不能访问枚举上的协变返回类型。重写枚举常量上的方法时,其类是匿名的。匿名类没有名称,无法引用。因此,程序员无法知道它的协变返回类型来使用它。此外,枚举不能声明泛型类型参数。因此,您想要做的事情在enum中根本不可能实现
可以使用带有
public static final
实例的类来模拟通用枚举:否则你需要彻底改变你的想法
# 2 楼答案
可能使用接口/抽象类而不是枚举
枚举不能有类型参数,但类和接口可以
例如
接口
实体。java
“东西”界面
存储库。java
积垢和东西混在一起
服务。java
一个服务负责处理一些事情
实体类
实体1。java
带字符串键的坚实基类
实体2。java
带整数键的实心基类
实体1服务。java
实体1服务
实体2服务。java
实体2服务
服务持有者。java
不是一个枚举,而是一个接口——你可以在这里添加一些方法来设置spring中的“服务”等等
有趣的部分
我想这是你想要的东西,如果我误解了,请告诉我
希望这有帮助